fix: weight:0 un-gates criteria + configurable retry policy#34
fix: weight:0 un-gates criteria + configurable retry policy#34uipreliga wants to merge 1 commit into
Conversation
|
Claude finished @uipreliga's task in 1m 59s —— View job Code Review In Progress
|
akshaylive
left a comment
There was a problem hiding this comment.
The weight 0 fix LGTM. The configurable retry policy should ideally be a separate PR. Additionally the retry policy configuration shouldn't be in "run_limits" (retry policy is not really a limit, so a separate top level field is better). I haven't looked too deep into the impl but would this clear the working directory between retries?
|
The evalboard change moves
|
ee9aa58 to
c746087
Compare
|
@akshaylive thanks — all three points taken. 1. Separate PR. Done. This PR is now the 2. 3. "Would this clear the working directory between retries?" No, it does not — good catch, and it's a real pre-existing gap rather than something the retry knob introduced:
I chose to document this rather than add a reset seam: clearing the sandbox mid-task would discard work the agent had already done and budget already spent, and preserving partials is deliberate (crash forensics). #44 adds a |
- weight: 0 now makes a criterion purely informational — excluded from both the weighted score AND the pass/fail gate (previously it could still flip a task to FAILURE). New BaseSuccessCriterion.is_gating drives the single-source gate (all_criteria_passed) and the `coder-eval evaluate` exit code. A validator rejects weight:0 combined with stop_when or suite_thresholds (arming a non-gating criterion for a pass/fail gate is incoherent). - reports.py failure-reason sampling uses pass_threshold, not score < 1.0. - Doc drift: dropped the non-existent `rephrase` mutation; corrected the stale "max_memory_mb NOT enforced" claim (docker --memory/--cpus/--pids-limit). Split out per review: the configurable retry policy moved to #44, and the evalboard OSS-edition change is dropped entirely (see @bai-uipath's review comment — the panels need core-produced fields that do not exist yet). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
c746087 to
8c02dc6
Compare
Split out of #34 per review, with the placement feedback applied. - New RetryPolicy (models/retry.py): max_retries / initial_delay / backoff_multiplier, all optional. It lives at the task's TOP LEVEL (`retry:`), not under `run_limits` — `run_limits` holds caps that abort a run, while a retry policy is how hard the run tries to survive a transient error. - `retry` is a first-class 4th `-D` root alongside agent/run_limits/sandbox: `-D retry.max_retries=0` to fail fast while debugging. It merges through the SAME resolve_root engine at every layer (experiment defaults, task, variant, CLI), so the unification invariant holds — covered by new test_merge_unification cases. - All retry decisions resolve through one seam, errors/retry.py:: resolve_retry_config. A category that is non-retryable in the built-in table (auth/billing) is never made retryable by a per-run override — retryability is a property of the error, not the run. - Persisted error_details.is_retryable / retry_delay_seconds now reflect the run's actual policy instead of the built-in defaults. - Docs: TASK_DEFINITION_GUIDE gains a `retry` section that documents the placement rationale AND the in-place retry semantics raised in review — a retried communicate() re-sends into the same sandbox and session (the working directory is NOT reset), and the crashed attempt's partial turn is preserved, so trajectory-observing criteria see both attempts. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
@bai-uipath you're right, and I've dropped the evalboard change from this PR entirely rather than argue it. The justification in my PR description — "they derive purely from run artifacts" — was true and answered the wrong question. Portability was the bar I checked; product fit is the bar that matters here, and I didn't check it. Your two specifics hold up when I trace them:
So a new adopter lands on a Watchlist with a dead column and an empty failure-tag panel, and reasonably concludes the page is broken. That's worse than not shipping it, exactly as you said. Dropping it also fixes a packaging problem @akshaylive flagged on the retry policy — this PR is now the If we do want these OSS-side later, the prerequisite is core actually emitting the fields the panels read ( |

Summary
Three independent fixes surfaced by a prior review, plus the code-review follow-ups on top of them.
1.
weight: 0now makes a criterion informationalPreviously a
weight: 0criterion contributed nothing to the weighted score but could still single-handedly flip a task toFAILURE— the docs told authors to also setpass_threshold: 0, which was easy to miss.BaseSuccessCriterion.is_gating(weight > 0.0) is the single source of truth for "does a low score here fail the task".EvaluationResult.all_criteria_passedand thecoder-eval evaluateexit code now gate overis_gatingcriteria only. Aweight: 0miss no longer flipsfinal_statusor the exit code.weight: 0combined withstop_whenorsuite_thresholds— arming a non-gating criterion for a pass/fail gate (early-stop gate, or the across-row suite gate that drives the run exit code) is incoherent and is now caught at load time.2. Configurable retry policy
RunLimits.retry(RetryPolicy:max_retries/initial_delay/backoff_multiplier, all optional) exposed via-D run_limits.retry.max_retries=0to fail fast while debugging.errors/retry.py::resolve_retry_config. A category that is non-retryable in the built-in table (auth/billing) is never made retryable by a per-run override — retryability is a property of the error, not the run.error_details.is_retryable/retry_delay_secondsintask.jsonnow reflect the run's actual policy instead of the built-in defaults.3. Doc drift + evalboard
rephraseprompt mutation from the catalog.max_memory_mbNOT enforced" claim (it maps todocker run --memory;max_cpus/max_pids→--cpus/--pids-limit).reports.pyfailure-reason sampling usespass_threshold, notscore < 1.0./trendsand/watchlistnow ship in the OSS edition (they derive purely from run artifacts); only/path-to-gastays internal-gated.Test plan
make verifygreen — 3437 passed, 2 skipped, 90.90% coverage, ruff + pyright + custom CE lint clean.weight: 0un-gating semantics, thestop_when/suite_thresholdsrejections, retry-policy resolution + fail-fast,error_detailspolicy fidelity, and acoder-eval evaluateexit-code test (with fixture) proving an informational miss doesn't fail the run.Follow-ups (not in this PR)
Display-only sites (terminal PASS/FAIL label,
reports_html, evalboard result pill,checkerlog line) still label a below-thresholdweight: 0criterion as failed.final_statusand both exit codes are correct; a clean fix needs a coordinated gating marker onCriterionResult/CriterionSummary+ the evalboard DTO, so it's deferred to avoid partial header-vs-list contradictions.🤖 Generated with Claude Code